import socket
import threading
import time
from typing import Optional, Callable
from datetime import datetime
from applications.protocols.file_transfer_protocol import FileTransferProtocol
from applications.utils.logger_utils import LoggerUtils

# 获取logger实例
logger = LoggerUtils.get_logger('tcp_server_log')


# 定义TCPClient类，封装客户端连接信息
class TCPClient:
    def __init__(self, socket_obj: socket.socket, address: tuple, name: str = "",
                 client_type: str = "", desc: str = ""):
        """
        初始化TCP客户端对象
        :param socket_obj: 客户端套接字对象
        :param address: 客户端地址
        :param name: 客户端名称
        :param client_type: 客户端类型
        :param desc: 客户端描述
        """
        self.socket = socket_obj
        self.address = address
        self.name = name
        self.addtime = datetime.now()
        self.type = client_type
        self.desc = desc


class TCPServer:
    def __init__(self, host: str, port: int,
                 data_handler=None, server_name="TCPServer"):
        """
        TCP服务器类初始化
        :param host: 监听IP地址
        :param port: 监听端口
        
        :param data_handler: 数据处理回调函数，格式: func(data: bytes, server: TCPServer, client_socket: socket.socket)
        """
        self.host = host
        self.port = port

        self.data_handler = data_handler
        self.server_socket = None
        self.is_running = False
        self.client_sockets = []
        self.server_name = server_name
        self.lock = threading.Lock()
        self.protocol = FileTransferProtocol()

    def start(self) -> bool:
        """启动TCP服务器"""
        try:
            # 创建TCP套接字
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            # 设置端口复用
            self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            # 绑定地址和端口
            self.server_socket.bind((self.host, self.port))
            # 开始监听，最大连接数5
            self.server_socket.listen(5)
            self.is_running = True
            logger.info(f" [{self.server_name}] TCP server started, listening on {self.host}:{self.port}")
            # 启动接受客户端连接的线程
            accept_thread = threading.Thread(target=self._accept_clients, daemon=True)
            accept_thread.start()
            return True
        except Exception as e:
            logger.error(f" [{self.server_name}] tcp server start failed, error: {str(e)}")
            self.stop()
            return False

    def _accept_clients(self) -> None:
        """接受客户端连接的内部方法"""
        while self.is_running and self.server_socket:
            try:
                # 接受客户端连接
                client_socket, client_address = self.server_socket.accept()
                # 创建TCPClient对象并添加到客户端列表
                tcp_client = TCPClient(client_socket, client_address)
                with self.lock:
                    self.client_sockets.append(tcp_client)
                logger.info(f" [{self.server_name}] new client connected: {client_address[0]}:{client_address[1]}")
                logger.info(f" [{self.server_name}] current client count: {len(self.client_sockets)}")
                message = self.protocol.pack_data(1, b"" + "欢迎连接到服务器，这里是".encode(
                    'utf-8') + self.server_name.encode('utf-8'))
                # 发送欢迎消息
                client_socket.sendall(message)

                # 启动处理客户端数据的线程
                client_thread = threading.Thread(
                    target=self._handle_client,
                    args=(tcp_client,),
                    daemon=True
                )
                client_thread.start()
            except Exception as e:
                if self.is_running:
                    logger.error(f" [{self.server_name}] client connect failed, error: {str(e)}")

    def _handle_client(self, tcp_client: TCPClient) -> None:
        # 处理客户端数据的内部方法
        client_info = f"客户端 [{tcp_client.address[0]}:{tcp_client.address[1]}]"
        if tcp_client.name:
            client_info += f" (名称: {tcp_client.name})"

        try:
            while self.is_running:
                # 调用数据处理回调函数，并检查返回值
                self.data_handler(tcp_client.socket)
        except ConnectionResetError:
            # 连接被客户端重置
            disconnect_reason = "连接被客户端重置"
            logger.warning(f" [{self.server_name}] {client_info} 断开连接: {disconnect_reason}")
        except ConnectionAbortedError:
            # 连接被中止
            disconnect_reason = "连接被中止"
            logger.warning(f" [{self.server_name}] {client_info} 断开连接: {disconnect_reason}")
        except BrokenPipeError:
            # 管道破裂（客户端已关闭）
            disconnect_reason = "管道破裂（客户端可能已关闭）"
            logger.warning(f" [{self.server_name}] {client_info} 断开连接: {disconnect_reason}")
        except TimeoutError:
            # 连接超时
            disconnect_reason = "连接超时"
            logger.warning(f" [{self.server_name}] {client_info} 断开连接: {disconnect_reason}")
        except socket.error as e:
            # 其他套接字错误
            disconnect_reason = f"套接字错误: {str(e)}"
            logger.error(f" [{self.server_name}] {client_info} 断开连接: {disconnect_reason}")
        except Exception as e:
            # 其他未预期的错误
            disconnect_reason = f"未知错误: {str(e)}"
            logger.error(f" [{self.server_name}] {client_info} 断开连接: {disconnect_reason}")
        finally:
            # 清理客户端连接
            with self.lock:
                if tcp_client in self.client_sockets:
                    self.client_sockets.remove(tcp_client)
            # 确保关闭套接字
            try:
                tcp_client.socket.shutdown(socket.SHUT_RDWR)
            except:
                pass  # 忽略可能已关闭的套接字错误
            try:
                tcp_client.socket.close()
            except:
                pass  # 忽略可能已关闭的套接字错误

            # 记录最终断开信息
            disconnection_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            connection_duration = datetime.now() - tcp_client.addtime
            hours, remainder = divmod(connection_duration.seconds, 3600)
            minutes, seconds = divmod(remainder, 60)
            duration_str = f"{hours}小时{minutes}分钟{seconds}秒"

            logger.info(
                f" [{self.server_name}] {client_info} 连接已完全关闭，连接时长: {duration_str},断开时间: {disconnection_time}")
            logger.info(f" [{self.server_name}] current client count: {len(self.client_sockets)}")

    def send_data(self, client_socket: socket.socket, data: bytes) -> bool:
        # 向指定客户端发送数据
        try:
            client_socket.sendall(data)
            return True
        except Exception as e:
            logger.error(f" [{self.server_name}] send data failed, error: {str(e)}")
            return False

    def broadcast(self, data: bytes) -> None:
        # 向所有连接的客户端广播数据 
        with self.lock:
            for tcp_client in self.client_sockets[:]:  # 使用副本避免迭代中修改
                self.send_data(tcp_client.socket, data)
        logger.info(f" [{self.server_name}] send data to {len(self.client_sockets)} clients")

    def stop(self) -> None:
        # 停止TCP服务器
        self.is_running = False
        # 关闭所有客户端连接
        with self.lock:
            for tcp_client in self.client_sockets:
                tcp_client.socket.close()
            self.client_sockets.clear()
        # 关闭服务器套接字
        if self.server_socket:
            self.server_socket.close()
            self.server_socket = None
        logger.info(f" [{self.server_name}] TCP server stopped")

    def __del__(self):
        # 析构函数，确保服务器正确停止
        if self.is_running:
            self.stop()
